using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace GuavaData
{
    public class Filter : Operator
    {
        // Filter is like a relational select operator.  Has 'or' semantics between conditions - to do 'and', just add another Filter operator

        #region Fields
        Operator child;
        public Operator Child
        {
            get { return child; }
            set { child = value; }
        }

        List<string> columnAliases;
        public List<string> ColumnAliases
        {
            get { return columnAliases; }
            set { columnAliases = value; }
        }

        List<Condition> columnConditions;
        public List<Condition> ColumnConditions
        {
            get { return columnConditions; }
            set { columnConditions = value; }
        }
        #endregion Fields

        public Filter(Operator child)
        {
            this.child = child;
            child.parent = this;
            this.columnAliases = new List<string>();
            this.columnConditions = new List<Condition>();

            this.exposedColumns = new List<string>(this.child.exposedColumns);
            this.exposedDomains = new List<GuavaData.Domain.Domain>(this.child.exposedDomains);
        }

        public Filter(Operator child, IEnumerable<string> columnAliases, IEnumerable<Condition> conditions)
        {
            this.child = child;
            child.parent = this;
            this.columnAliases = new List<string>(columnAliases);
            this.columnConditions = new List<Condition>(conditions);

            this.exposedColumns = new List<string>(this.child.exposedColumns);
            this.exposedDomains = new List<GuavaData.Domain.Domain>(this.child.exposedDomains);
        }

        public override SqlText Visit(Provider qv)
        {
            return qv.Transform(this);
        }
        public override void Visit(Transform t, Command c)
        {
            t.Expand(this, c);
        }
        public override Operator Clone()
        {
            return new Filter(this.child, this.columnAliases, this.columnConditions);
        }

        public override void NotifyChange(Operator old, Operator newOp)
        {
            if (this.child == old)
            {
                this.child = newOp;
                newOp.parent = this;
            }
        }

        public void AddCondition(string column, Condition condition)
        {
            this.columnAliases.Add(column);
            this.columnConditions.Add(condition);
        }

        public string ConditionString
        {
            get
            {
                if (columnAliases.Count <= 0)
                    return "";
                String o = "";
                if (columnConditions[0].CondType == ConditionType.ARB) o = columnConditions[0].ToString();
                else o = columnAliases[0] + columnConditions[0].ToString();

                for (int i = 1; i < columnAliases.Count; i++)
                {
                    //String column = "[" + columnAliases[i].Split('.')[1] + "]";
                    //o = String.Concat(o, " OR ", columnAliases[i].Split('.')[0], ".", column, columnConditions[i].ToString());
                    if (columnConditions[0].CondType == ConditionType.ARB) String.Concat(o, " OR ", columnConditions[i].ToString());
                    o = String.Concat(o, " OR ", columnAliases[i], columnConditions[i].ToString());
                }
                return o;
            }
        }

        public override void Visit(Channel c, string table)
        {
            c.MapAliases(this, table);
        }

        new public static Filter FromXElement(XElement x)
        {
            
            List<string> aliases = new List<string>();
            List<GuavaData.Condition> conditions = new List<Condition>();
            List<object> args = null;
            Operator child = null;
            //GuavaData.Condition cnd = null;
            


            foreach (XElement att in x.Elements())
            {
                if (att.Name.LocalName.Equals("operator")) child = Operator.FromXElement(att);
                else if (att.Name.LocalName.Equals("condition"))
                {
                    aliases.Add(att.Attribute("column").Value);
                    args = new List<object>();
                    foreach (XElement el in att.Elements())
                    {
                        args.Add(el.Value);
                    }
                    conditions.Add(GuavaData.Condition.NewCondition((ConditionType) 
                        (Enum.Parse(typeof (ConditionType), att.Attribute("op").Value)),args));
                   /* switch (att.Attribute("op").Value)
                    {
                        case "BETWEEN":
                            conditions.Add(new GuavaData.BETCond(args));
                            break;
                        case "CONTAINS":
                            conditions.Add(new GuavaData.ContainsCond(args));
                            break;
                        case "EQ":
                            conditions.Add(new GuavaData.EQCond(args));
                            break;
                        case "GE":
                            conditions.Add(new GuavaData.GECond(args));
                            break;
                        case "GT":
                            conditions.Add(new GuavaData.GTCond(args));
                            break;
                        case "ISNOTNULL":
                            conditions.Add(new GuavaData.NotNullCond(args));
                            break;
                        case "ISNULL":
                            conditions.Add(new GuavaData.NullCond(args));
                            break;
                        case "LE":
                            conditions.Add(new GuavaData.LECond(args));
                            break;
                        case "LT":
                            conditions.Add(new GuavaData.LTCond(args));
                            break;
                        case "NEQ":
                            conditions.Add(new GuavaData.NEQCond(args));
                            break;
                        
                           
                        

                    }*/
                }
            }

            if (!(child == null))
                return new Filter(child, aliases, conditions);
            else
                throw new Exception("While loading Filter from XML: child was null");
        }

        }
}
